package org.gbif.crawler;

import org.gbif.api.model.registry.Endpoint;
import org.gbif.api.vocabulary.EndpointType;

import java.io.Serializable;
import java.util.Comparator;
import java.util.List;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;

/**
 * Compares two Endpoints.
 * <p/>
 * It does so by first checking the {@code preferred} flag and then by using a priority list of Endpoint Types.
 * This Comparator will throw a {@link ClassCastException} exception if a non supported EndpointType is passed in. It
 * also does not support {@code null} values.
 * <p/>
 * The priority list is as follows (most to least important):
 * <ol>
 * <li>DwC-A</li>
 * <li>DwC-A (Occurrences)</li>
 * <li>DwC-A (Checklist)</li>
 * <li>TAPIR</li>
 * <li>BioCASe</li>
 * <li>DiGIR</li>
 * <li>DiGIR (Manis)</li>
 * </ol>
 */
public class EndpointPriorityComparator implements Comparator<Endpoint>, Serializable {

  private static final long serialVersionUID = 8085216142750609841L;

  // Priorities from lowest to highest
  public static final List<EndpointType> PRIORITIES =
    ImmutableList.of(EndpointType.DIGIR_MANIS, EndpointType.DIGIR, EndpointType.BIOCASE, EndpointType.TAPIR,
      EndpointType.DWC_ARCHIVE_CHECKLIST, EndpointType.DWC_ARCHIVE_OCCURRENCE, EndpointType.DWC_ARCHIVE);


  private static final Ordering<EndpointType> PRIORITY_COMPARATOR = Ordering.explicit(PRIORITIES);
  private static final Comparator<EndpointType> ENDPOINT_TYPE_COMPARATOR = new Comparator<EndpointType>() {

    @Override
    public int compare(EndpointType type1, EndpointType type2) {
      return PRIORITY_COMPARATOR.compare(type1, type2);
    }

  };

  @Override
  public int compare(Endpoint endpoint1, Endpoint endpoint2) {
    // Sort first by preferred status
    int preferredResult = Boolean.valueOf(endpoint1.isPreferred()).compareTo(endpoint2.isPreferred());
    if (preferredResult != 0) {
      return preferredResult;
    }

    // Next by Endpoint type
    return ENDPOINT_TYPE_COMPARATOR.compare(endpoint1.getType(), endpoint2.getType());
  }

}
